﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace CrankShaftAnalysisSystem
{
    public class VirtualDevice : ModbusProxy
    {
        public class Address
        {
            public const int Axis1Speed = 8;
            public const int Axis2Speed = 22;
            public const int Axis3Speed = 36;
            public const int PLCCommand = 42;
        }

        public class Mask
        {
            public const ushort EMERGENCY = 0x0100; // 急停
            public const ushort SAFTEY = 0x0200; // 光栅
            public const ushort PROXIMITY0 = 0x0400; // 接近开关
            public const ushort PROXIMITY1 = 0x0800; // 接近开关
            public const ushort PROXIMITY2 = 0x1000; // 接近开关
            public const ushort PROXIMITY3 = 0x2000; // 接近开关

            public const ushort CHANGEPART = 0x0100; // 换料
            public const ushort FALLDOWN = 0x0200; // 顶尖下落
            public const ushort AUTOSTART = 0x0400; // 自动启动
            public const ushort RESET = 0x0800; // 复位
            public const ushort MANUALON = 0x1000; // 手动
            public const ushort AUTOON = 0x2000; // 自动
            public const ushort RESERVED = 0x4000; // 预留
            public const ushort STOP = 0x8000; // 停止

            public const ushort PARTEXIST = 0x0100; // 检测到零件
            public const ushort PNEUMATICPOS0 = 0x0200; // 气缸位置，右边气缸顶出
            public const ushort PNEUMATICPOS1 = 0x0400; // 气缸位置，右边气缸缩回
            public const ushort PNEUMATICPOS2 = 0x0800; // 气缸位置，左边气缸顶出
            public const ushort PNEUMATICPOS3 = 0x1000; // 气缸位置，左边气缸缩回
            public const ushort VACCUMM = 0x2000;
            public const ushort AUTOLED = 0x4000;

        }
        public VirtualDevice(string ip, int port) : base(ip, port)
        {
            RegisterAdress = 0x0000;  // PLC默认是从0开始的
            RegisterLength = 68;
            OnGetHoldingRegisters += VirtualDevice_OnGetHoldingRegisters;
            Axises = new MotorInfo_T[3] {
                new MotorInfo_T(),
                new MotorInfo_T(),
                new MotorInfo_T()
            };
            Info = new PLCInfo_T();
        }

        public bool StateRefreshed { get; private set; } = false;

        public MotorInfo_T Axis1 {
            get
            {
                return Axises[0];
            }
        }  // 底部旋转台
        public MotorInfo_T Axis2 {
            get
            {
                return Axises[1];
            }
        }   // 左边电机
        public MotorInfo_T Axis3 {
            get
            {
                return Axises[2];
            }
        }   // 右边电机

        public double Temperature1
        {
            get
            {
                return Info.Temperature1 / 10.0;
            }
        }

        public double Temperature2
        {
            get
            {
                return Info.Temperature2 / 10.0;
            }
        }

        public double Temperature3
        {
            get
            {
                return Info.Temperature3 / 10.0;
            }
        }

        public MotorInfo_T[] Axises;
        public PLCInfo_T Info;

        public void VirtualDevice_OnGetHoldingRegisters(ushort[] regs)
        {
            StateRefreshed = true;
            var axis_len = Marshal.SizeOf(Axises[0]);
            var info_len = Marshal.SizeOf(Info);
            int reg_size = axis_len / 2;  // 寄存器是16位的，所以寄存器数量是总字节数的一半
            short[] sregs = new short[regs.Length];
            for(int i=0;i<sregs.Length;i++)
            {
                sregs[i] = (short)regs[i];
            }
            IntPtr p_axis = Marshal.AllocHGlobal(axis_len);
            IntPtr p_info = Marshal.AllocHGlobal(info_len);
            for (int i = 0; i < 3; i++)
            {
                Marshal.Copy(sregs, i* reg_size, p_axis, reg_size);
                Axises[i] = (MotorInfo_T)Marshal.PtrToStructure(p_axis, Axises[i].GetType());
            }
            // 从地址42开始是和PLC直接相关的信息
            Marshal.Copy(sregs, 42, p_info, info_len / 2);
            Info = (PLCInfo_T)Marshal.PtrToStructure(p_info, Info.GetType());
            Marshal.FreeHGlobal(p_axis);
            Marshal.FreeHGlobal(p_info);
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public class MotorInfo_T
        {
            public ushort DriverStatus { get; set; }
            public ushort Errorno { get; set; }
            public short ActualVel { get; set; }
            public ushort PLCSetEncoderClearCmd { get; set; }
            public ushort PLCSetClearAlarmCmd { get; set; }
            public ushort EncoderSingleTurnLM { get; set; }
            public ushort EncoderSingleTurnH { get; set; }
            public ushort EncoderMultiTurn { get; set; }
            public ushort CommandVelL { get; set; }
            public ushort CommandVelH { get; set; }
            public ushort EncoderClearCmd { get; set; }
            public ushort ClearAlarmCmd { get; set; }
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public ushort[] Reserved;

            public MotorInfo_T()
            {
                Reserved = new ushort[2];
            }
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public class PLCInfo_T
        {
            public ushort Axis1AtZero { get; set; }
            public ushort PenCompressionReached { get; set; }

            public ushort MT2571Out { get; set; }
            public ushort MT2571Back { get; set; }

            public ushort VacuumOn { get; set; }
            public ushort VacuumOff { get; set; }
            public ushort CommunicationCnt { get; set; }
            public ushort Temperature1 { get; set; }
            public ushort Temperature2 { get; set; }
            public ushort Temperature3 { get; set; }

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
            public ushort[] HoldingRegs;

            // PLC里面接下来就是位信息了
            public ushort SafeInfo { get; set; }
            public ushort ButtonInfo { get; set; }
            public ushort FeedBackInfo { get; set; }
            public ushort Others { get; set; }
            public PLCInfo_T()
            {
                HoldingRegs = new ushort[12];
            }
        }
    }
}
